package EA.operators.selection;
import EA.*;
import RKUjava.util.RKUValuation;
import RKUjava.lang.RKUCloneable;


/** This class implements binary tournament selection.
    <br><b>Note:</b> If you want to clone the objects you must
    implement the interface RKUCloneable.
    @see RKUjava.lang.RKUCloneable
*/
public class TournamentSelection extends Selection
{
  
  /** Perform a tournament selection among the sources. <br>
      <b>Note:</b> The source objects must implement the interface RKUValuation
      from the package RKUjava.util. When using this method the object with
      highest value is selected. Objects are NOT cloned.
      @param sources The object to select between. 
      @param numberofselected The size of the resulting array.
  */
  public static Object[] select(Object[] sources, int numberofselected)
  {
    return selectInto(sources, numberofselected, true, false, 0, sources.length, new Object[numberofselected]);
  }

  /** Perform a tournament selection among the sources. <br>
      <b>Note:</b> The source objects must implement the interface RKUValuation
      from the package RKUjava.util. Objects are NOT cloned.
      @param sources The object to select between. 
      @param numberofselected The size of the resulting array.
      @param maximization Boolean indicating whether this is a maximization or
      minimization selection.
  */
  public static Object[] select(Object[] sources, int numberofselected, boolean maximization)
  {
    return selectInto(sources, numberofselected, maximization, false, 0, sources.length, new Object[numberofselected]);
  }

  /** Perform a tournament selection among the sources. <br>
      <b>Note:</b> The source objects must implement the interface RKUValuation
      from the package RKUjava.util. 
      @param sources The object to select between. 
      @param numberofselected The size of the resulting array.
      @param maximization Boolean indicating whether this is a maximization or
      minimization selection.
      @param cloneobjects Boolean indicating whether you want to clone the 
      selected object. (Remember to implement cloneable)
  */
  public static Object[] select(Object[] sources, int numberofselected, boolean maximization, boolean cloneobjects)
    {
      return selectInto(sources, numberofselected, maximization, cloneobjects, 0, sources.length, new Object[numberofselected]);
    }

  /** Perform a selection among the sources in the chosen range. <br>
      <b>Note:</b> The source objects must implement the interface RKUValuation
      from the package RKUjava.util. Passing 0 in <tt>lowerindex</tt> and 
      sources.length in <tt>upperindex</tt> will perform a selection among all
      objects in the sources-array.
      @param sources The object to select between. 
      @param numberofselected The size of the resulting array.
      @param maximization Boolean indicating whether this is a maximization or
      minimization selection.
      @param cloneobjects Boolean indicating whether you want to clone the 
      selected object. (Remember to implement cloneable)
      @param lowerindex The lower index of the range.
      @param upperindex The upper index of the range + 1. 
  */
  public static Object[] select(Object[] sources, int numberofselected, boolean maximization, boolean cloneobjects, int lowerindex, int upperindex)
  {
      return selectInto(sources, numberofselected, maximization, cloneobjects, lowerindex, upperindex, new Object[numberofselected]);
  }

    /** Perform a selection among the sources and place the selected in an array. <br>
      <b>Note:</b> The source objects must implement the interface RKUValuation
      from the package RKUjava.util. When using this method the object with
      highest value is selected. Objects are NOT cloned.
      @param sources The object to select between. 
      @param numberofselected The size of the resulting array.
      @param destination The array to place the selected in. MUST be big 
      enough to hold all entries.
      @return The array passed as <tt>destination</tt>.
  */
  public static Object[] selectInto(Object[] sources, int numberofselected, Object[] destination)
    {
    return selectInto(sources, numberofselected, true, false, 0, sources.length, destination);
    };

  /** Perform a selection among the sources and place the selected in an array. <br>
      <b>Note:</b> The source objects must implement the interface RKUValuation
      from the package RKUjava.util. Objects are NOT cloned.
      @param sources The object to select between. 
      @param numberofselected The size of the resulting array.
      @param maximization Boolean indicating whether this is a maximization or
      minimization selection.
      @param destination The array to place the selected in. MUST be big 
      enough to hold all entries.
      @return The array passed as <tt>destination</tt>.
  */
  public static Object[] selectInto(Object[] sources, int numberofselected, boolean maximization, Object[] destination) 
    {
	return selectInto(sources, numberofselected, maximization, false, 0, sources.length, destination);
    };

  /** Perform a selection among the sources and place the selected in an array. <br>
      <b>Note:</b> The source objects must implement the interface RKUValuation
      from the package RKUjava.util. 
      @param sources The object to select between. 
      @param numberofselected The size of the resulting array.
      @param maximization Boolean indicating whether this is a maximization or
      minimization selection.
      @param cloneobjects Boolean indicating whether you want to clone the 
      selected object. (Remember to implement cloneable)
      @param destination The array to place the selected in. MUST be big 
      enough to hold all entries.
      @return The array passed as <tt>destination</tt>.
  */
  public static Object[] selectInto(Object[] sources, int numberofselected, boolean maximization, boolean cloneobjects, Object[] destination) 
    {
      return selectInto(sources, numberofselected, maximization, cloneobjects, 0, sources.length, destination);
    };

  /** Perform a selection among the sources in the chosen range and place the selected in an array. <br>
      <b>Note:</b> The source objects must implement the interface RKUValuation
      from the package RKUjava.util. Passing 0 in <tt>lowerindex</tt> and 
      sources.length in <tt>upperindex</tt> will perform a selection among all
      objects in the sources-array.
      @param sources The object to select between. 
      @param numberofselected The size of the resulting array.
      @param maximization Boolean indicating whether this is a maximization or
      minimization selection.
      @param cloneobjects Boolean indicating whether you want to clone the 
      selected object. (Remember to implement cloneable)
      @param lowerindex The lower index of the range.
      @param upperindex The upper index of the range + 1. 
      @param destination The array to place the selected in. MUST be big 
      enough to hold all entries.
      @return The array passed as <tt>destination</tt>.
  */
  public static Object[] selectInto(Object[] sources, int numberofselected, boolean maximization, boolean cloneobjects, int lowerindex, int upperindex, Object[] destination)
  {
    int i, index1, index2;
    int candidates;

    candidates = upperindex-lowerindex;

    if (maximization==true && cloneobjects==false) {
      for (i=0;i<numberofselected;i++) {
	index1 = lowerindex+UsefulRoutines.randomInt(candidates);
	index2 = lowerindex+UsefulRoutines.randomInt(candidates);
	if (((RKUValuation)sources[index1]).value()>=((RKUValuation)sources[index2]).value())
	  destination[i] = sources[index1];
	else
	  destination[i] = sources[index2];
      }
    }
    else if (maximization==true && cloneobjects==true) {
      for (i=0;i<numberofselected;i++) {
	index1 = lowerindex+UsefulRoutines.randomInt(candidates);
	index2 = lowerindex+UsefulRoutines.randomInt(candidates);
	if (((RKUValuation)sources[index1]).value()>=((RKUValuation)sources[index2]).value())
	  destination[i] = ((RKUCloneable)sources[index1]).clone();
	else
	  destination[i] = ((RKUCloneable)sources[index2]).clone();
      }
    }
    else if (maximization==false && cloneobjects==false) {
      for (i=0;i<numberofselected;i++) {
	index1 = lowerindex+UsefulRoutines.randomInt(candidates);
	index2 = lowerindex+UsefulRoutines.randomInt(candidates);
	if (((RKUValuation)sources[index1]).value()<=((RKUValuation)sources[index2]).value())
	  destination[i] = sources[index1];
	else
	  destination[i] = sources[index2];
      }
    }
    else if (maximization==false && cloneobjects==true) {
      for (i=0;i<numberofselected;i++) {
	index1 = lowerindex+UsefulRoutines.randomInt(candidates);
	index2 = lowerindex+UsefulRoutines.randomInt(candidates);
	if (((RKUValuation)sources[index1]).value()<=((RKUValuation)sources[index2]).value())
	  destination[i] = ((RKUCloneable)(sources[index1])).clone();
	else
	  destination[i] = ((RKUCloneable)(sources[index2])).clone();
      }
    }
    return destination;
    };


}
